package ijeoma.tween;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;

import processing.core.PApplet;

public class TweenSequence extends TweenPlugin {
	
	private int tweensIndex = 0;

	public Object currentObject, lastObject;
	private Tween currentTween;
	private TweenGroup currentTweenGroup;

	private String objectMode = "";

	private Method tweenSequenceStartedMethod, tweenSequenceEndedMethod,
			tweenSequenceChangedMethod, tweenSequenceRepeatedMethod;

	public TweenSequence(PApplet _parent) {
		super(_parent);
		setupEvents();
	}

	public TweenSequence(PApplet _parent, Object[] _tweens) {
		super(_parent, _tweens); 
		setupEvents();
	}

	private void setupEvents() {
		try {
			tweenSequenceStartedMethod = parent.getClass().getMethod(
					TweenEvent.TWEEN_SEQUENCE_STARTED + "Event",
					new Class[] { TweenSequence.class });
			tweenSequenceEndedMethod = parent.getClass().getMethod(
					TweenEvent.TWEEN_SEQUENCE_ENDED + "Event",
					new Class[] { TweenSequence.class });
			tweenSequenceChangedMethod = parent.getClass().getMethod(
					TweenEvent.TWEEN_SEQUENCE_CHANGED + "Event",
					new Class[] { TweenSequence.class });
			tweenSequenceRepeatedMethod = parent.getClass().getMethod(
					TweenEvent.TWEEN_SEQUENCE_REPEATED + "Event",
					new Class[] { TweenSequence.class });
		} catch (Exception e) {
		}
	}

	public void start() {
		isTweening = true;
		dispatchTweenSequenceStartedEvent();

		tweensIndex = 0;

		startObject();
	}

	private void startObject() {
		if (currentObject != null)
			lastObject = currentObject;

		currentObject = items.get(tweensIndex);

		if (currentObject.getClass().getSimpleName().equals("Tween")) {
			objectMode = TWEEN;
			currentTween = (Tween) currentObject;
			currentTween.start();
		} else {
			objectMode = TWEENGROUP;
			currentTweenGroup = (TweenGroup) currentObject;
			currentTweenGroup.start();
		}
	}

	public void end() {
		isTweening = false;
		dispatchTweenSequenceEndedEvent();
	}

	private void next() {
		dispatchTweenSequenceChangedEvent();

		if (tweensIndex < items.size() - 1) {
			tweensIndex++;
			startObject();
		} else if ((tweensIndex == items.size() - 1)) {
			if (isRepeating && (repeatTimes == 0 || repeatTimes < repeatCount)) {
				repeatCount++;
				dispatchTweenSequenceRepeatedEvent();

				if (repeatMode == REVERSE)
					reverse();

				start();
			} else {
				end();
			}
		}
	}

	public void update() {
		if (isTweening) {
			if (objectMode == TWEEN)
				currentTween.update();
			else
				currentTweenGroup.update();
		}
	}

	public void reverse() {
		Collections.reverse(items);
		start();
	}

	public Object getCurrentObject() {
		return items.get(tweensIndex);
	}

	public void onTweenEvent(TweenEvent te) {
		if (isDebugging)
			PApplet.println(te.getSource() + "." + te.type);

		if (te.type == TweenEvent.TWEEN_ENDED
				|| te.type == TweenEvent.TWEEN_GROUP_ENDED) {
			next();
		}
	}

	public void dispatchTweenSequenceStartedEvent() {
		dispatchEvent(TweenEvent.TWEEN_SEQUENCE_STARTED);

		if (tweenSequenceStartedMethod != null) {
			try {
				tweenSequenceStartedMethod
						.invoke(parent, new Object[] { this });
			} catch (Exception e) {
				e.printStackTrace();
				tweenSequenceStartedMethod = null;
			}
		}
	}

	public void dispatchTweenSequenceEndedEvent() {
		dispatchEvent(TweenEvent.TWEEN_SEQUENCE_ENDED);

		if (tweenSequenceEndedMethod != null) {
			try {
				tweenSequenceEndedMethod.invoke(parent, new Object[] { this });
			} catch (Exception e) {
				e.printStackTrace();
				tweenSequenceEndedMethod = null;
			}
		}
	}

	public void dispatchTweenSequenceChangedEvent() {
		dispatchEvent(TweenEvent.TWEEN_SEQUENCE_CHANGED);

		if (tweenSequenceChangedMethod != null) {
			try {
				tweenSequenceChangedMethod
						.invoke(parent, new Object[] { this });
			} catch (Exception e) {
				e.printStackTrace();
				tweenSequenceChangedMethod = null;
			}
		}
	}

	public void dispatchTweenSequenceRepeatedEvent() {
		dispatchEvent(TweenEvent.TWEEN_SEQUENCE_REPEATED);

		if (tweenSequenceRepeatedMethod != null) {
			try {
				tweenSequenceRepeatedMethod.invoke(parent,
						new Object[] { this });
			} catch (Exception e) {
				e.printStackTrace();
				tweenSequenceRepeatedMethod = null;
			}
		}
	}

	public String toString() {
		String tweenNames = "";

		for (int i = 0; i < items.size(); i++) {
			if (items.get(i).getClass().getSimpleName().equals("Tween"))
				tweenNames += ((Tween) items.get(i)).name;
			else
				tweenNames += ((TweenGroup) items.get(i)).toString();
		}

		return ("TweenSequence[tweens: {" + tweenNames + "}]");
	}
}
